package com.cskaoyan.javase.array._4operation._5copy;

import java.util.Arrays;

/**
 * 数组的长度是不可以改变的
 * 所以如果想要实现数组元素"真正意义上的"删除和新增，是不可能在原先数组上直接进行的
 * 一般需要使用数组的拷贝。
 *
 * 大致思路是，创建一个新数组,然后拷贝赋值：
 *      1.首先需要明确新数组的长度，初始化这个新数组。
 *      2.然后遍历原先的数组，过滤掉（或者新增）一些元素，给新数组赋值。
 *
 *
 * @since 17:51
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class ArrCopyDemo {
    public static void main(String[] args) {
        int[] old = {10, 2, 30, 4, 5};
        int[] result = realAddElementInIntArr(old, 6);
        System.out.println(Arrays.toString(result));
        System.out.println("----------------------");


        int[] old2 = {1, 2, 3, 1, 1, 2, 3, 4, 2, 3};
        System.out.println(Arrays.toString(old2));

        int[] result2 = realDeleteElementInIntArr(old2, 4);
        System.out.println(Arrays.toString(result2));
    }

    // 需求1: 给出一个int类型数组,直接新增一个元素
    /*
        不可能真正的直接在原先数组上新增一个元素
        所以必须要创建一个新数组,将老数组中元素赋值过去,然后插入一个新元素

        有以下问题:
            1,新数组创建,那么它的长度是多少?
                老数组的长度 + 1

            2,新数组创建出来以后,如何赋值?
                首先需要将老数组中的所有元素,全部复制过去
                这时新数组就只剩下一个空位置了
                这个空位置就是留个那个新增元素的

           3,方法的返回值类型怎么写?方法需不需要返回值?
                肯定是需要的
                新数组在方法内部被创建出来
                如果不返回给方法外部,那么外部就拿不到这个新数组,方法就没有意义
                所以方法的返回值类型应该写: int[]
                将新数组返回给外部.
     */

    /**
     * 利用数组元素的拷贝,将一个元素真正意义上插入一个数组
     * 该方法会返回插入一个元素后的新数组
     *
     * @param old 被插入元素的旧数组
     * @param target 被插入的元素
     * @return int[]
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/07/07 18:43
     */
    public static int[] realAddElementInIntArr(int[] old, int target) {
        /*if (_0old == null || _0old.length == 0) {
            System.out.println("非正常数组!");
            return null;
        }*/
        // 1.首先创建新数组,新数组的长度 = 老数组的长度 + 1
        int[] result = new int[old.length + 1];

        /*
            新数组的下标,从0开始,然后每赋值一次,该下标+1
            由于新数组的长度是老数组长度+1,所以这里无需担心数组越界
         */
        int newIndex = 0;
        // 2.新数组创建完毕后,给新数组中的元素赋值
        // 遍历老数组,将其中的每一个元素都赋值到新数组中
        for (int element : old) {
            result[newIndex] = element;
            newIndex++;
        }
        // 把新增的元素,赋值到新数组的最后一个位置
        result[result.length - 1] = target;
        return result;
    }


    // 需求2: 给出一个int数组,要求真正的删除某个元素,注意该元素可能不唯一,要求全部删除
    /*
         分析:
         不可能真正的直接在原先数组上删除元素(数组长度不可变)
         所以必须要创建一个新数组,然后删除元素表现为,将老数组中不删除的元素赋值进新数组
         所以删除元素,实际上是过滤元素,过滤掉那些要被删除的元素

         存在以下问题:
                1.新数组的长度是什么?
                    老数组的长度 - 被删除元素的个数

                2.被删除元素的个数怎么算?
                    遍历老数组,逐一比对,然后计数(重要)

                3.如何给新数组赋值?
                    所谓删除元素,实际上是过滤老数组中的元素
                    所以只要遍历判断,如果是被删除元素,那就跳过不赋值
                        反之如果不是被删除元素,那就赋值.
     */

    /**
     * 真正意义上删除目标元素,需要创建新数组
     * @param old 被删除元素的老数组
     * @param target 被删除的目标元素,可能不唯一
     * @return int[]
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/07/08 9:57
     */
    public static int[] realDeleteElementInIntArr(int[] old, int target) {
        // 1.计数,算出被删除元素的个数
        // 计数,需要计数器,一般都是一个int类型的count
        int count = 0;
        for (int ele : old) {
            if (ele == target) {
                count++;
            }
        }
        // 遍历完整个数组,程序运行到这里,count就是被删除元素的个数
        // 2.创建新数组,新数组的长度 = 老数组的长度 - 被删除元素的个数
        int[] result = new int[old.length - count];

        // 3.过滤给新数组赋值
        // 这个过程,仍然是需要遍历老数组
        // newIndex表示新数组的下标,新数组在循环中每赋值一次,该下标都要加1
        int newIndex = 0;
        for (int ele : old) {
            if (ele == target) {
                // 该元素是被删除的元素,那就不赋值
                continue;
            }
            // 不是被删除元素,那就赋值给新数组
            result[newIndex] = ele;
            newIndex++;
        }
        // 新数组赋值结束,返回新数组
        return result;
    }
}
